package com.cloud.point.concurrent.general;

import java.util.concurrent.TimeUnit;

import lombok.extern.slf4j.Slf4j;

/**
 * Wait-Notify使用
 *
 * @author 24373
 * @version 1.0
 * @date 2024-06-15 16:01
 */
@Slf4j
public class TestWaitNotify {

    static final Object lock = new Object();
    static boolean flag = false;
    static boolean flag2 = false;

    public static void main(String[] args) throws InterruptedException {

        Thread t1 = new Thread(() -> {
            synchronized (lock) {
                log.info("t1线程启动");
                while (!flag) {
                    try {
                        log.info("t1线程等待执行");
                        lock.wait(3000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                log.info("t1线程结束");
            }
        });
        t1.start();

        Thread t2 = new Thread(() -> {
            synchronized (lock) {
                log.info("t2线程启动");
                /**
                 *  获取了锁，但条件不满足，进入等待
                 *  while循环等待，防止虚假唤醒
                 */
                while (!flag2) {
                    try {
                        /**
                         * 等待并且让出锁
                         */
                        log.info("t2线程等待执行");
                        lock.wait(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                // 唤醒后接着执行线程
                log.info("t2线程结束");
            }
        });
        t2.start();

        for (int i = 0; i < 3; i++) {
            new Thread(() -> {
                synchronized (lock) {
                    log.info("其它线程启动");
                }
            }).start();
        }

        TimeUnit.SECONDS.sleep(1);

        synchronized (lock) {
            log.info("main线程启动");
            flag = true;
            //唤醒所有等待的线程；等待线程会有虚假唤醒情况
            lock.notifyAll();
            log.info("main线程唤醒");
        }

    }

    /**
     * wait/notify使用
     * 交替打印字母A/B
     * 如果需要更严格的交替顺序（例如，一个字母总是在另一个字母之后打印），那么要采用更复杂的方法，比如使用Semaphore或CyclicBarrier等并发工具
     */
    static final Object lock2 = new Object();

    private void test() {
        Thread threadA = new Thread(() -> {
            synchronized (lock2) {
                for (int i = 0; i < 50; i++) {
                    log.info("A");
                    /**
                     * 唤醒所有等待的线程；等待线程竞争时会自旋一下等待锁释放
                     */
                    lock2.notifyAll();
                    try {
                        lock2.wait(500);
                    } catch (InterruptedException e) {
                        Thread.currentThread().interrupt();
                    }
                }
            }
        });

        Thread threadB = new Thread(() -> {
            synchronized (lock2) {
                for (int i = 0; i < 50; i++) {
                    log.info("B");
                    lock2.notifyAll();
                    try {
                        lock2.wait(500);
                    } catch (InterruptedException e) {
                        Thread.currentThread().interrupt();
                    }
                }
            }
        });

        threadA.start();
        threadB.start();

    }

}
